package com.muyu.chat.utils;

import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.opencv.global.opencv_calib3d;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.*;
import org.bytedeco.opencv.opencv_features2d.BFMatcher;
import org.bytedeco.opencv.opencv_features2d.ORB;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.bytedeco.opencv.global.opencv_core.CV_32FC2;
import static org.bytedeco.opencv.global.opencv_core.NORM_HAMMING;

public class ForgeryVerifier {

    public static class Region {
        public int x, y, width, height;
        public Region(int x, int y, int w, int h) {
            this.x = x; this.y = y; this.width = w; this.height = h;
        }
    }

    /**
     * 把 List<Point2f> 转成 Mat(Nx1, CV_32FC2)，用于 findHomography
     */
    private static Mat toPointMat(List<Point2f> pts) {
        Mat mat = new Mat(pts.size(), 1, CV_32FC2);
        for (int i = 0; i < pts.size(); i++) {
            Point2f p = pts.get(i);
            // Mat.ptr(i) 返回该行的指针，putFloat(offset, value) 写float，float占4字节
            mat.ptr(i).putFloat(0, p.x());
            mat.ptr(i).putFloat(4, p.y());
        }
        return mat;
    }

    /**
     * 关键点匹配 + 计算单应性矩阵，带完整RANSAC参数，返回对齐后的 imgTest
     */
    public static Mat alignImages(Mat imgRef, Mat imgTest) {
        ORB orb = ORB.create();
        KeyPointVector kp1 = new KeyPointVector();
        KeyPointVector kp2 = new KeyPointVector();
        Mat desc1 = new Mat();
        Mat desc2 = new Mat();

        orb.detectAndCompute(imgRef, new Mat(), kp1, desc1);
        orb.detectAndCompute(imgTest, new Mat(), kp2, desc2);

        BFMatcher matcher = new BFMatcher(NORM_HAMMING, true);
        DMatchVector matches = new DMatchVector();
        matcher.match(desc1, desc2, matches);

        List<Point2f> pts1 = new ArrayList<>();
        List<Point2f> pts2 = new ArrayList<>();

        for (long i = 0; i < matches.size(); i++) {
            DMatch m = matches.get(i);
            pts1.add(kp1.get(m.queryIdx()).pt());
            pts2.add(kp2.get(m.trainIdx()).pt());
        }

        if (pts1.size() < 4 || pts2.size() < 4) {
            throw new RuntimeException("匹配点数不足，无法计算单应矩阵");
        }

        Mat srcPts = toPointMat(pts2);
        Mat dstPts = toPointMat(pts1);

        Mat mask = new Mat();
        int method = opencv_calib3d.RANSAC;
        double ransacThreshold = 3.0;
        int maxIters = 2000;
        double confidence = 0.995;

        Mat homography = opencv_calib3d.findHomography(
                srcPts,
                dstPts,
                method,
                ransacThreshold,
                mask,
                maxIters,
                confidence
        );

        Mat aligned = new Mat();
        opencv_imgproc.warpPerspective(imgTest, aligned, homography, imgRef.size());

        return aligned;
    }

    public static Mat cropRegion(Mat image, Region r) {
        return new Mat(image, new Rect(r.x, r.y, r.width, r.height));
    }

    /**
     * 计算两张图像 8x8 灰度感知哈希相似度
     * 返回 0~1，1 表示完全相同
     */
    public static double compareHash(Mat img1, Mat img2) {
        Mat r1 = new Mat();
        Mat r2 = new Mat();
        opencv_imgproc.resize(img1, r1, new Size(8, 8));
        opencv_imgproc.resize(img2, r2, new Size(8, 8));
        opencv_imgproc.cvtColor(r1, r1, opencv_imgproc.COLOR_BGR2GRAY);
        opencv_imgproc.cvtColor(r2, r2, opencv_imgproc.COLOR_BGR2GRAY);

        double avg1 = meanGray(r1);
        double avg2 = meanGray(r2);
        int[] hash1 = toHash(r1, avg1);
        int[] hash2 = toHash(r2, avg2);

        int diffCount = 0;
        for (int i = 0; i < 64; i++) {
            if (hash1[i] != hash2[i]) diffCount++;
        }

        return 1.0 - (diffCount / 64.0);
    }

    private static double meanGray(Mat mat) {
        double sum = 0;
        BytePointer ptr;
        for (int y = 0; y < mat.rows(); y++) {
            ptr = mat.ptr(y);
            for (int x = 0; x < mat.cols(); x++) {
                int v = ptr.get(x) & 0xFF;
                sum += v;
            }
        }
        return sum / (mat.rows() * mat.cols());
    }

    private static int[] toHash(Mat mat, double avg) {
        int[] hash = new int[64];
        BytePointer ptr;
        int i = 0;
        for (int y = 0; y < mat.rows(); y++) {
            ptr = mat.ptr(y);
            for (int x = 0; x < mat.cols(); x++) {
                int v = ptr.get(x) & 0xFF;
                hash[i++] = v > avg ? 1 : 0;
            }
        }
        return hash;
    }

    public static void main(String[] args) {
        Mat ref = opencv_imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\111.png");
        Mat test = opencv_imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\444.png");

        if (ref.empty() || test.empty()) {
            System.err.println("无法加载图片！");
            return;
        }

        Mat aligned = alignImages(ref, test);

        List<Region> regions = Arrays.asList(
                new Region(100, 100, 50, 50),
                new Region(300, 300, 50, 50),
                new Region(500, 200, 50, 50)
        );

        for (int i = 0; i < regions.size(); i++) {
            Mat r1 = cropRegion(ref, regions.get(i));
            Mat r2 = cropRegion(aligned, regions.get(i));
            double similarity = compareHash(r1, r2);
            System.out.printf("防伪点 %d 相似度: %.3f%n", i + 1, similarity);
        }
    }
}
